Chapter 14 / Configuration Management

Manajemen Konfigurasi

DNA aplikasi Anda, cara kode yang sama berperilaku berbeda lintas lingkungan tanpa pernah menyentuh codebase.


Versi Sederhana

01 / DEFINITION

Apa Itu Manajemen Konfigurasi?

Config management is the systematic approach to organize, store, access and maintain all the settings of our backend app.

Jika mengikuti definisi, manajemen konfigurasi (atau sekadar "config management") adalah pendekatan sistematis untuk mengorganisasi, menyimpan, mengakses, atau pada dasarnya memelihara semua setelan aplikasi backend kita. Kata kuncinya setelan.

Anda bisa menganggap konfigurasi sebagai DNA aplikasi Anda. Ia memutuskan cara kode Anda berjalan di lingkungan berbeda. Kode aplikasi yang sama persis bisa berperilaku dengan cara yang sepenuhnya berbeda hanya karena konfigurasinya, dan itu memang desainnya.

Kesalahpahaman Umum

Saat Anda bilang "manajemen konfigurasi" ke kebanyakan orang, kesan pertama, gagasan pertama yang muncul, adalah menyimpan hal-hal seperti:

  • Kata sandi database dan URL koneksi aman database Anda
  • Kunci autentikasi aman, secret key untuk JWT secret Anda, dll.
  • API key layanan eksternal, seperti layanan pengiriman email Anda

Itulah yang terlintas kapan pun kita bicara config management. Tapi berpikir begitu melewatkan banyak cakupannya.

The Car Analogy

Menganggap config management hanya soal secret dan URL DB itu seperti bilang "mobil cuma soal mesin." Mesin jelas bagian terpenting mobil, tapi Anda masih melewatkan 90% fitur mobil lainnya. Begitu pula, manajemen konfigurasi punya banyak dimensi lain.

Cakupan Penuh Config Management

Manajemen konfigurasi sebenarnya mencakup rentang perilaku aplikasi yang luas:

  • Cara aplikasi Anda mulai: urutan bootstrap dan apa yang ia butuhkan untuk mulai berjalan
  • Cara ia terhubung ke layanan eksternal: database, cache, message queue, API pihak ketiga
  • Cara ia berperilaku di lingkungan berbeda: perilaku dev vs staging vs produksi
  • Apa yang ia log, apakah ia log, dan ke mana ia log: perilaku dan tujuan logging
  • Ke mana ia mengirim metrik: tujuan metrik performa dan metrik bisnis
  • Fitur mana yang diaktifkan atau dinonaktifkan: untuk versi deployment ini, dan untuk pengguna mana

Cakupan config management luas. Ia tidak terbatas pada URL database atau secret key Anda, ia memengaruhi banyak perilaku penting aplikasi backend Anda. Persis itulah kenapa topik ini begitu penting.


02 / WORKED EXAMPLE

Contoh Platform E-Commerce

Katakanlah Anda membangun platform e-commerce, dan Anda mengerjakan backend-nya. Konfigurasi Anda mungkin mencakup banyak hal, masing-masing dengan karakteristik sangat berbeda. Mari telusuri setiap kategori yang dibutuhkan backend semacam itu.

E-commerce backend configuration categories E-Commerce Backend Config DB Connection host, port, user, pass, timeout Payment API Keys e.g. Stripe keys Feature Flags new vs old checkout Performance Tuning connection pool size Security Settings session timeouts Business Rules max order amount
Fig 1.1: The six configuration categories of an e-commerce backend

Mengurai tiap kategori secara detail:

  • Detail koneksi database: detail timeout, host, port, username, password, dll. Semua detail koneksi database Anda.
  • API key pemroses pembayaran: jika memakai Stripe, API key Stripe Anda ada di sini.
  • Feature flag: fitur apa yang diaktifkan untuk deployment ini dan yang tetap dinonaktifkan. Contohnya: Anda membangun alur checkout baru, dan sebuah feature flag mengendalikan apakah Anda masih memakai alur checkout lama atau yang baru. Anda bahkan bisa mengaktifkan alur baru secara kondisional untuk sebagian pengguna dan alur lama untuk yang lain.
  • Parameter tuning performa: seperti ukuran connection pool Anda (pool yang dipakai untuk koneksi database).
  • Setelan keamanan: seperti session timeout, apakah 30 detik, 60 detik, dll.
  • Aturan bisnis: untuk e-commerce, ini bisa memuat hal seperti jumlah order maksimum yang diizinkan untuk seorang pengguna.

Kenapa Config Ini Punya Karakteristik Berbeda

Setiap konfigurasi ini punya karakteristik yang fundamental berbeda, dan mengenali perbedaannya menggerakkan setiap keputusan soal cara menyimpan dan melindunginya:

KarakteristikContohImplikasi
Sensitif / rahasiaPassword DB, key Stripe, JWT secretTidak boleh pernah bocor, bisa menyebabkan kerugian/kerusakan besar
Non-rahasia tapi pengendali perilakuLog level, feature flag, ukuran poolMengendalikan cara aplikasi berperilaku saat runtime
Sering berubahFeature flag selama rolloutButuh jalur pembaruan cepat dan dinamis
Jarang berubahAturan bisnis (bulanan/triwulanan)Bisa disimpan lebih statis
Sama di semua lingkunganAturan bisnis tertentuConfig bersama
Berbeda per lingkunganHost DB, ukuran pool, log levelConfig spesifik lingkungan

Sebagian sensitif dan harus dijaga rahasia, membocorkannya bisa menimbulkan banyak kerusakan dan kerugian. Sebagian bukan rahasia tapi mengendalikan cara aplikasi Anda berperilaku saat berjalan. Sebagian berubah sering; yang lain berubah sebulan sekali atau seperempat sekali. Sebagian tetap sama di development, staging, dan produksi; yang lain berbeda tergantung lingkungannya. Keberagaman inilah alasan inti config management butuh strategi sungguhan.


03 / THE CHALLENGE

Tantangan Sistem Terdistribusi

Di atas semua keberagaman itu duduk satu tantangan besar: sistem terdistribusi. Kebanyakan aplikasi modern kita, semua backend modern kita, tidak lagi berjalan terisolasi. Kebanyakan kini bagian dari sistem terdistribusi yang kompleks.

Sistem terdistribusi terdiri dari banyak bagian yang bergerak:

  • Banyak service
  • Database
  • Cache (seperti Redis)
  • Message queue
  • Integrasi pihak ketiga
  • Penyedia autentikasi
  • Layanan email
  • ...dan masih banyak lagi

Semua titik integrasi berbeda ini, tempat Anda menghubungkan layanan terpisah ke backend utama Anda, semuanya butuh konfigurasi. Backend Anda jelas perlu tahu cara terhubung ke layanan ini. Tapi di atas itu, ia juga perlu tahu:

  • Cara menangani kegagalan: apa yang terjadi saat sebuah layanan mati atau lambat
  • Cara mengoptimalkan performa: tergantung lingkungan dan setelan
  • Cara menjaga keamanan: tergantung lingkungan dan sumber config

Semua ini bergantung pada lingkungan berbeda, setelan berbeda, dan config berbeda, yang bisa kita kendalikan dari sumber berbeda. Inilah alasan, karena kebanyakan backend modern berjalan di sistem terdistribusi, manajemen konfigurasi menjadi bagian begitu penting dari aplikasi Anda.

Why Backend Config Stakes Are So High

Taruhannya lebih tinggi bagi engineer backend karena mereka menangani logika bisnis dan data inti: boleh dibilang bagian terpenting platform atau perusahaan mana pun. Frontend yang salah konfigurasi mungkin menampilkan fitur yang salah, dialog yang tak seharusnya tampil, atau mengarahkan ke route yang salah, mengesalkan, tapi bisa dipulihkan. Backend yang salah konfigurasi bisa mengekspos data pelanggan, memproses pembayaran dengan salah, atau merobohkan seluruh platform Anda jika bagian penting terdampak. Radius ledakannya sangat besar.

Dan sistem backend berjalan di lingkungan beragam, penyedia cloud berbeda, server on-premises, container, fungsi serverless, fungsi edge, dan semuanya punya kebutuhan konfigurasi berbeda. Tidak ada satu target seragam, yang membuat pendekatan sistematis menjadi esensial.


04 / THE ANTI-PATTERN

Kekacauan Konfigurasi

Jika Anda tidak punya pendekatan sistematis, jika tidak punya pipeline khusus, strategi khusus untuk mengelola config Anda, Anda akan berakhir dengan yang kita sebut configuration chaos.

Configuration chaos berarti alih-alih mengendalikan config dari satu titik terpusat, Anda punya kekacauan. Begini rupanya:

Nilai hard-coded yang tersebar

Nilai konfigurasi di-hard-code dan tersebar di seluruh codebase alih-alih tinggal di satu tempat terpusat.

Perilaku tidak konsisten

Aplikasi Anda berperilaku tidak konsisten lintas lingkungan karena config tidak dikelola seragam.

Kerentanan keamanan

Secret yang terekspos bocor ke codebase, version control, dan log, menciptakan lubang keamanan nyata.

Mimpi buruk debugging

Anda tidak bisa mereproduksi masalah karena tidak ada cara terpusat mengelola config. Anda tidak tahu config mana yang menyebabkan kerusakan mana di produksi.

Poin terakhir ini pembunuhnya: men-debug aplikasi Anda menjadi mimpi buruk karena Anda tidak bisa mereproduksi masalahnya. Anda tidak benar-benar tahu apa yang persis terjadi, config khusus apa yang menyebabkan masalah khusus apa, atau config khusus apa yang menyebabkan kerusakan di produksi. Config management terpusat itulah yang memberi Anda keterlacakan itu.


05 / TYPES

Jenis-jenis Konfigurasi

Tidak semua konfigurasi diciptakan sama. Memahami jenis berbeda dari data konfigurasi sangat penting untuk memilih mekanisme penyimpanan, langkah keamanan, dan pola akses yang tepat: siapa bisa mengakses apa, dan di lingkungan mana sebuah config tertentu seharusnya bisa diakses. Mari telusuri tiap jenis.

5.1: Application Settings

Jenis config paling umum yang akan Anda lihat di kebanyakan aplikasi backend. Ini mencakup:

  • Log level: Di development kita set log level ke debug supaya bisa melihat dan membedakan log saat membangun aplikasi lokal. Di produksi kita ubah ke info supaya tidak mengotori log produksi yang berharga.
  • Port: Port mana backend berjalan. Biasanya 8080 secara lokal; di produksi (VPS atau Kubernetes) Anda mungkin punya port berbeda.
  • Ukuran connection pool: Ukuran pool maksimum untuk koneksi database Anda. Aplikasi backend memakai connection pooling untuk mengoptimalkan koneksi DB.
  • Nilai timeout: Berapa lama server harus menunggu sebuah request selesai.
Timeout Example / The AI Image Case

Anggap Anda set server timeout 60 detik, dan Anda memulai request yang menghasilkan gambar AI (dikembalikan ke frontend dalam base64). Jika generasi gambar AI rata-rata ±80 detik, tapi timeout server Anda 60 detik, request Anda dibuang: Anda akan dapat status 504 Gateway Timeout. Konfigurasi timeout secara langsung menentukan apakah request lambat yang sah berhasil atau gagal.

5.2: Konfigurasi Database

Config database mencakup semua detail yang dibutuhkan aplikasi Anda untuk terhubung ke database:

  • Host: tempat database Anda berjalan
  • Port: port database
  • Username: user database
  • Password: kata sandi database (sensitif!)
  • Nama database: DB spesifik yang dihubungi

Semua parameter ini digabungkan memungkinkan Anda menyusun URL koneksi, yang dipakai aplikasi Anda saat runtime untuk terhubung ke database. Ia mungkin juga punya parameter lain, seperti query timeout (berapa lama sebuah query database boleh berjalan sebelum timeout).

5.3: Layanan Eksternal

Layanan eksternal datang dalam banyak jenis, dan masing-masing punya kebutuhan konfigurasi sendiri, biasanya semacam API key:

  • Penyedia email: Mailchimp, Resend, dll. -> Anda butuh API key untuk memulai klien dan mengirim email
  • Pemroses pembayaran: Stripe -> API key Stripe
  • Penyedia autentikasi: Clerk -> API key Clerk

Tidak peduli penyedia mana yang Anda pakai, Anda kemungkinan besar punya semacam API key di config yang harus Anda urus.

5.4: Feature Flag

Feature flag ada supaya Anda bisa secara dinamis mengaktifkan atau menonaktifkan fitur tertentu aplikasi Anda tanpa mengubah kode.

Feature flag A/B testing by region Feature Flag new_checkout_enabled US users -> NEW checkout flag = true India users -> OLD checkout flag = false conditional rollout by location
Fig 2.1: Feature flag enabling new checkout for US users while India keeps the old flow (A/B testing)

Contoh klasiknya: Anda membangun alur checkout baru (memakai API berbeda) dan tidak ingin merilisnya ke semua pengguna sekaligus. Anda ingin A/B testing: hanya mengaktifkan fitur baru untuk segmen pengguna tertentu tergantung lokasinya. Misalnya, aktifkan checkout baru untuk pengguna dari AS, tapi pertahankan alur lama untuk pengguna dari India. Feature flag membuat pengaktifan/penonaktifan dinamis ini mungkin, dan ia juga butuh config management.

5.5: Tipe Config Lain

Di luar empat kategori utama, ada beberapa lagi:

  • Infra config: Semua konfigurasi terkait DevOps Anda.
  • Security config: JWT secret Anda, session secret, dan apa pun terkait keamanan yang memengaruhi aplikasi Anda.
  • Tuning performa: Jika backend Anda dibangun dengan Go (Golang), Anda bisa set environment variable seperti jumlah CPU maksimum (GOMAXPROCS), dll.
  • Aturan bisnis: Aturan terkait logika berbeda yang ingin Anda tegakkan di level aplikasi, tapi dipusatkan di config alih-alih di-hard-code.

06 / STORAGE

Sumber Config (Penyimpanan)

Dengan semua kebutuhan config beragam ini, kita juga harus memikirkan di mana menyimpan config-nya. Tempat Anda menyimpan konfigurasi bergantung banyak parameter, keamanan, kecepatan, dan lingkungan Anda. Mari lihat mekanisme penyimpanan utamanya.

6.1: Environment Variable

Jenis penyimpanan config paling umum yang dilihat kebanyakan orang. Jika Anda pernah bekerja dengan backend, Anda pernah menjumpai file .env. Ini paling umum di aplikasi Node.js, tapi juga didukung di Python, Go, dan bahasa apa pun tempat Anda membangun backend.

Cara kerjanya secara lokal

Di lingkungan lokal, Anda punya file bernama .env. Library yang sangat terkenal bernama dotenv mengambil semua environment variable Anda dari file .env dan memuatnya ke environment sistem operasi Anda.

Important Distinction

Environment variable adalah fitur yang disediakan sistem operasi Anda: ini bukan sesuatu yang Anda bangun. Library seperti dotenv hanya mengambil nilai dari file dan memuatnya ke environment Anda otomatis, alih-alih Anda melakukannya manual dengan perintah export.

Cara kerjanya saat deployment

Jika tidak lokal, katakanlah Anda deploy di lingkungan containerized memakai Kubernetes, teknologi itu juga mendukung pemuatan environment variable saat men-deploy aplikasi Anda. Inilah alur kerja deployment cloud yang khas:

Cloud deployment env var loading workflow Deployment triggers Fetch secrets from Vault / Param Store Azure / GCP Secret Mgr at a particular stage Load into env OS environment App starts reads env, runs Deployment -> fetch from secret manager -> load into environment -> app boots
Fig 3.1: Cloud deployment env var workflow: deploy triggers fetch from a secrets service, loads into the environment, app reads on startup

Deployment terpicu; pada tahap tertentu ia mengambil semua environment variable Anda dari sebuah layanan, Vault (HashiCorp), Parameter Store, Azure, atau Google Secret Manager (penyedia cloud mana pun yang menawarkan manajemen secret), dan memuatnya ke environment Anda. Lalu saat aplikasi Anda mulai, ia membaca environment variable itu dan berfungsi sesuai. Ini mekanisme penyimpanan config paling umum.

6.2: File Config

Jenis penyimpanan kedua adalah file, yang datang dalam format berbeda:

FormatMendukung komentar?Catatan
JSONTidakKelemahan besar, tidak bisa menambah komentar, jadi lebih sulit berbagi pengetahuan tim
YAMLYaKini lebih terkenal untuk config; mendukung komentar untuk berbagi pengetahuan tim
TOMLYaStandar lebih baru, juga banyak dipakai untuk mengelola konfigurasi

Salah satu kelemahan utama JSON adalah Anda tidak bisa menambah komentar: JSON tidak mendukung komentar. Itulah kenapa kebanyakan orang memakai YAML: Anda bisa menambah konfigurasi dan komentar supaya lebih mudah berbagi pengetahuan tim. TOML standar lebih baru yang juga populer.

Real-World Examples

Authelia (penyedia autentikasi yang ditulis Go) memakai file configuration.yaml yang memegang setelan server, log level (debug), penyimpanan, detail notifikasi, detail identitas, regulasi, setelan sesi, semuanya dalam satu file YAML. Apache Answer (incubator, open source) juga memakai config.yaml di banyak tempat, setelan aplikasi seperti port tempat server berjalan, database (SQLite untuk lingkungan lokal), dan config Swagger UI. Menyimpan konfigurasi di YAML sangat umum di repositori open source.

6.3: Key-Value Store & Penyedia Cloud

Key-Value Store

Di luar nilai env sederhana, ada tool cloud-native khusus seperti Consul dan etcd. Tergantung kasus pakai Anda, Anda bisa memakai salah satunya. Key-value store cukup ringan dan sederhana dipakai dibanding struktur data hirarkis yang lebih rumit untuk manajemen config. Ia bertindak sebagian besar seperti environment variable Anda.

Secret Manager Cloud Khusus

Di sini pemain utamanya:

  • HashiCorp Vault
  • AWS Parameter Store
  • Azure Key Vault
  • Google Secret Manager

Ini layanan khusus untuk manajemen config dan secret yang dipakai kebanyakan perusahaan, karena deployment zaman sekarang terdistribusi, Kubernetes, autoscaling, kadang beberapa penyedia cloud sekaligus demi kebutuhan scaling. Memiliki semua konfigurasi terpusat di tool seperti HashiCorp Vault, yang sudah mendukung semua lingkungan berbeda ini, dengan dokumen dan integrasi khusus, membuat integrasinya semudah mungkin. Memakai penyedia eksternal masuk akal besar jika Anda menjalankan lalu lintas pengguna berat di produksi.

Strategi Hibrida

Kebanyakan waktu, tim sebenarnya memakai strategi hibrida. Anda punya fase pemuatan tempat Anda menyusun setelan aplikasi runtime dengan mengambil config dari banyak tempat, masing-masing dengan prioritas:

Hybrid config loading with priority 1. AWS Parameter Store highest priority 2. config.yaml file middle priority 3. Environment variables fallback / defaults Loading phase merge by priority Runtime Settings single config object
Fig 3.2: Hybrid config loading: multiple sources merged by priority into one runtime settings object

Misalnya, di prioritas pertama Anda mungkin mengambil dari AWS Parameter Store, lalu dari config.yaml, lalu dari environment variable. Anda memutuskan di awal sumber mana yang prioritasnya lebih tinggi, dan tergantung lingkungannya Anda memuat config itu secara kondisional. Ini memberi fleksibilitas: secret dari vault, setelan terstruktur dari file, dan override dari env var, semua digabung menjadi satu config runtime.


07 / ENVIRONMENTS

Kenapa Config Berbeda Per Lingkungan

Satu pertanyaan wajar: kenapa kita punya config berbeda tergantung lingkungan tempat kita berjalan? Jawabannya sederhana, setiap lingkungan punya satu set prioritas yang tidak dibutuhkan atau seharusnya tidak dimiliki lingkungan lain.

Four environments and their priorities Development developer productivity + debugging Test automated validation + quality assurance Staging mirror production catch issues early Production reliability, security + performance
Fig 4.1: The four environments and their distinct priorities

Menapaki prioritas tiap lingkungan:

  • Development (lokal): Berjalan di localhost. Prioritas nomor satu produktivitas developer dan kemampuan debugging: supaya Anda bisa bekerja lebih cepat dan menangkap masalah lebih cepat.
  • Test: Anda memicu GitHub Action yang menyiapkan lingkungan pengujian untuk menjalankan integration test, unit test, dll. Prioritasnya validasi otomatis dan jaminan kualitas.
  • Staging: Versi ter-hosting aplikasi Anda yang berfungsi semirip mungkin dengan produksi, jadi Anda punya gambaran jelas bagaimana produksi akan berperilaku dan bisa memperbaiki/men-debug masalah sesuai. Prioritasnya mencerminkan produksi.
  • Production: Yang sesungguhnya. Prioritasnya keandalan, keamanan, dan performa.
The Whole Point / Code Stays the Same

Kita membuat config dengan mengingat prioritas ini. Kode aplikasinya tetap sama di semua lingkungan, tapi tergantung config-nya, perilakunya berubah. Persis yang kita inginkan. Tanpa mengubah kode (yang harus kita lakukan jika meng-hard-code), config management terpusat berarti kita tidak pernah menyentuh kode aplikasi. Kita cukup mengubah config, dan itu tercermin di perilaku.

Contoh Kerja: Ukuran Pool Database Lintas Lingkungan

Ambil ukuran connection pool database sebagai contoh konkret bagaimana setelan yang sama berbeda per lingkungan:

LingkunganUkuran Pool MaksAlasan
Development10Bekerja baik secara lokal; mesin dev kelas atas modern punya cukup kapasitas untuk pengujian/pengembangan
Staging2Sengaja minimal untuk menghemat biaya cloud: kita terima keterlambatan karena ia dipakai dev/tester
Production50Harus menangani basis pengguna besar dan lonjakan lalu lintas, jadi ukuran pool lebih tinggi dibutuhkan

Di produksi Anda set ukuran pool ke 50 karena harus melayani basis pengguna besar dan bersiap lonjakan lalu lintas. Di development, 10 bekerja baik. Yang menarik staging: meski prioritas utama staging mencerminkan produksi semirip mungkin untuk menangkap masalah lebih awal, menjalankan sistem yang berfungsi persis seperti produksi akan berbiaya sama di tagihan cloud, dan itu bukan yang diinginkan kebanyakan tim.

The Cost Tradeoff in Staging

Staging punya prioritas sekunder: meminimalkan biaya cloud. Karena staging biasanya hanya dipakai developer dan tester, Anda bisa membuat keputusan seperti menjaga ukuran pool database minimal (mis. 2). Anda menampung sedikit keterlambatan di sana, tapi menghemat banyak uang di biaya cloud. Ini kompromi yang disengaja dan didorong config, dan ia mungkin justru karena ukuran pool hidup di config, bukan kode.


08 / SECURITY

Keamanan Konfigurasi

Ini poin yang cukup jelas, tapi demi mencakup cakupan penuh, layak dinyatakan eksplisit. Ada lima praktik keamanan kunci untuk config management.

8.1: Jangan Pernah Hardcode Secret

Jika Anda punya secret seperti URL database produksi, API key layanan Clerk Anda, layanan pengiriman email, atau layanan pemrosesan pembayaran, Anda tidak boleh pernah meng-hardcode secret itu di codebase. Ini begitu jelas sampai hampir tak perlu dijelaskan: secret yang di-hardcode berakhir di version control, terekspos di log, dan menjadi liabilitas permanen.

8.2: Pakai Cloud Secrets Manager

Jika mungkin, selalu pilih layanan manajemen secret cloud, HashiCorp Vault, AWS Parameter Store, Azure Key Vault, atau Google Secret Manager. Selalu ide bagus untuk "over-engineer" soal keamanan aplikasi backend Anda.

Layanan ini sudah menangani fitur keamanan kritis secara otomatis:

Encryption at rest and in transit Secret Manager encrypted at rest encrypted in transit (API call) Your Infra decrypt w/ private key App uses config decrypted, in memory Encrypted both at rest (storage) and in transit (transfer)
Fig 5.1: Secret managers encrypt configs at rest AND in transit; decryption happens with your private key in your infra
  • Enkripsi saat diam (at rest): Tidak peduli di mana mereka menyimpan config Anda; kapan pun menyimpannya, mereka mengenkripsinya dulu, lalu menyimpannya di database/penyimpanan mereka.
  • Enkripsi saat transit: Saat Anda membuat panggilan API untuk mengambil config, mereka mengirim versi terenkripsi. Dengan private key Anda (disimpan di infra, GitHub Action, repository secret, atau environment Kubernetes), config di-decode lalu dipakai.

Ini fitur keamanan esensial, dan saat Anda memakai penyedia cloud seperti Vault atau Parameter Store, semua ini sudah diurus, Anda tidak perlu memikirkannya.

8.3: Kontrol Akses (Least Privilege)

Jika Anda punya tim developer yang cukup besar, luangkan waktu menyusun strategi siapa yang boleh mengakses config mana, mengikuti prinsip least privilege:

  • Frontend developer: hanya boleh mengakses config yang mereka butuhkan: URL API backend dan API key untuk integrasi frontend.
  • Engineer backend: hanya boleh mengakses database, instance Redis, Elasticsearch, dll.
  • Hanya tim DevOps: config untuk mengakses instance cloud (mis. instance EC2) harus dibatasi ke DevOps.

Mengikuti prinsip least privilege, Anda menyusun strategi kontrol akses supaya setiap orang hanya punya akses ke yang benar-benar mereka butuhkan.

8.4: Rotasi

Anda harus secara berkala memutar semua config Anda, API key secret, JWT secret, dan nilai sensitif serupa, supaya tidak rentan bocor. Rotasi rutin membatasi jendela kerusakan jika sebuah secret pernah dikompromikan.

8.5: Validasi (Poin Terpenting)

Kebanyakan waktu, tim tidak memvalidasi environment variable atau sumber config apa pun. Dengan dotenv, misalnya, Anda memuat semua variabel ke environment dan mengaksesnya via process.env.WHATEVER, tanpa pemeriksaan.

The One Thing to Take Away From This Whole Topic

Jika Anda hanya membawa satu hal: selalu validasi config Anda, dari sumber mana pun. Validasi saat startup, sebelum aplikasi Anda mulai, tepat setelah ia di-deploy. Pakai library validasi yang layak: backend TypeScript -> pakai Zod; backend Go -> pakai go-playground/validator. Pakai library validasi apa pun yang ditawarkan bahasa/framework Anda, dan validasi dengan benar setiap variabel, mana yang wajib, mana yang opsional, mana yang punya default di kode aplikasi.

Kenapa ini begitu penting? Itu dipelajari dengan cara yang pahit. Jika Anda punya persyaratan environment variable wajib tapi gagal menyediakannya, sistem produksi Anda entah rusak atau berperilaku aneh karena tidak punya akses ke environment variable tertentu, dan itu tidak mudah terlihat. Memvalidasi saat startup mengubah kegagalan produksi yang senyap dan misterius menjadi pesan error yang keras, langsung, dan jelas yang memberi tahu Anda config mana yang persis hilang.


09 / CODE

Contoh Kode

Di bawah ini implementasi praktis pemuatan dan validasi config di Go dan Python, mencakup env var, pemuatan per-lingkungan, sumber hibrida, dan validasi startup.

9.1: Pemuatan & Validasi Config di Go

config.go / Go + go-playground/validator + godotenv
package config

import (
    "fmt"
    "log"
    "os"
    "strconv"

    "github.com/go-playground/validator/v10"
    "github.com/joho/godotenv"
)

// Config holds all runtime application settings.
// The `validate` tags enforce rules at startup, this is the
// single most important safeguard for config management.
type Config struct {
    // Application settings
    Port     int    `validate:"required,min=1,max=65535"`
    LogLevel string `validate:"required,oneof=debug info warn error"`
    Env      string `validate:"required,oneof=development staging production"`

    // Database config (sensitive)
    DBHost     string `validate:"required"`
    DBPort     int    `validate:"required"`
    DBUser     string `validate:"required"`
    DBPassword string `validate:"required"`
    DBName     string `validate:"required"`
    DBPoolSize int    `validate:"required,min=1"`

    // External services (sensitive)
    StripeAPIKey string `validate:"required"`

    // Feature flags (optional, default false)
    NewCheckoutEnabled bool
}

// DatabaseURL constructs the connection URL from the parts.
func (c *Config) DatabaseURL() string {
    return fmt.Sprintf(
        "postgres://%s:%s@%s:%d/%s",
        c.DBUser, c.DBPassword, c.DBHost, c.DBPort, c.DBName,
    )
}

// Load reads env vars, applies defaults, then VALIDATES before returning.
// Called once at startup, fail loudly here, never silently in production.
func Load() (*Config, error) {
    // In local dev, load .env into the OS environment.
    // In production this is a no-op (vars already injected by the platform).
    _ = godotenv.Load()

    cfg := &Config{
        Port:               getEnvInt("PORT", 8080),        // default 8080
        LogLevel:           getEnv("LOG_LEVEL", "info"),    // default info
        Env:                getEnv("APP_ENV", "development"),
        DBHost:             os.Getenv("DB_HOST"),
        DBPort:             getEnvInt("DB_PORT", 5432),
        DBUser:             os.Getenv("DB_USER"),
        DBPassword:         os.Getenv("DB_PASSWORD"),
        DBName:             os.Getenv("DB_NAME"),
        DBPoolSize:         getEnvInt("DB_POOL_SIZE", 10),  // dev=10, prod=50
        StripeAPIKey:       os.Getenv("STRIPE_API_KEY"),
        NewCheckoutEnabled: getEnv("NEW_CHECKOUT", "false") == "true",
    }

    // THE critical step, validate everything before the app boots
    if err := validator.New().Struct(cfg); err != nil {
        return nil, fmt.Errorf("config validation failed: %w", err)
    }

    return cfg, nil
}

func getEnv(key, fallback string) string {
    if v := os.Getenv(key); v != "" {
        return v
    }
    return fallback
}

func getEnvInt(key string, fallback int) int {
    if v := os.Getenv(key); v != "" {
        if n, err := strconv.Atoi(v); err == nil {
            return n
        }
    }
    return fallback
}

// Usage in main.go:
//   cfg, err := config.Load()
//   if err != nil { log.Fatal(err) }  // crash early, crash loud

9.2: Pemuatan & Validasi Config di Python

config.py / Python + pydantic-settings (the Python equivalent of Zod)
from enum import Enum
from functools import lru_cache

from pydantic import Field, computed_field
from pydantic_settings import BaseSettings, SettingsConfigDict


class Environment(str, Enum):
    DEVELOPMENT = "development"
    STAGING = "staging"
    PRODUCTION = "production"


class Settings(BaseSettings):
    """
    All runtime config. pydantic VALIDATES every field automatically
    when the object is constructed, mandatory fields without a default
    raise an error immediately at startup, not silently in production.
    """
    model_config = SettingsConfigDict(
        env_file=".env",        # load .env in local dev
        env_file_encoding="utf-8",
        case_sensitive=False,
    )

    # Application settings (with sensible defaults)
    port: int = Field(default=8080, ge=1, le=65535)
    log_level: str = Field(default="info", pattern="^(debug|info|warn|error)$")
    app_env: Environment = Environment.DEVELOPMENT

    # Database config, mandatory, no defaults (will fail if missing)
    db_host: str
    db_port: int = 5432
    db_user: str
    db_password: str          # sensitive, never hardcoded
    db_name: str
    db_pool_size: int = Field(default=10, ge=1)  # dev=10, prod=50, staging=2

    # External services, mandatory secret
    stripe_api_key: str

    # Feature flag, optional, defaults off
    new_checkout_enabled: bool = False

    @computed_field
    @property
    def database_url(self) -> str:
        return (
            f"postgresql://{self.db_user}:{self.db_password}"
            f"@{self.db_host}:{self.db_port}/{self.db_name}"
        )


@lru_cache  # load & validate once, reuse everywhere (singleton)
def get_settings() -> Settings:
    # Construction triggers validation. If a mandatory var is
    # missing, pydantic raises here, at startup, loudly.
    return Settings()


# Usage:
#   settings = get_settings()   # crashes early if config invalid
#   print(settings.database_url)
#   if settings.new_checkout_enabled: ...

9.3: Contoh File Config YAML

Untuk setelan non-rahasia yang terstruktur, file YAML (dengan komentar, tidak seperti JSON) pilihan umum, seperti yang terlihat di codebase nyata seperti Authelia dan Apache Answer:

config.yaml / structured app settings (non-secret)
# Server settings, note: YAML supports comments, JSON does not
server:
  port: 8080
  timeout_seconds: 60      # raise this for slow ops like AI image gen

log:
  level: debug             # debug in dev, info in production

database:
  host: localhost
  port: 5432
  name: ecommerce
  pool_size: 10            # dev=10, staging=2, prod=50
  query_timeout_seconds: 30

# Feature flags, dynamically enable/disable features
features:
  new_checkout_enabled: false
  rollout_regions: ["US"]   # A/B test: US gets new checkout

# Business rules, centralized, not hardcoded
business:
  max_order_amount: 500000

# NOTE: secrets (db password, Stripe key, JWT secret) do NOT
# belong here, those come from a secrets manager / env vars.

REFERENCES

Bacaan Lanjutan & Dokumentasi

Tool Manajemen Secret

Key-Value / Config Store

Library Validasi

Format File Config & Library

MDN Web Docs

BACKEND ENGINEERING FIELD MANUAL / V2 / BAB 13 / MANAJEMEN KONFIGURASI. Catatan disusun dari transkrip kuliah / contoh Go + Python / referensi Vault/MDN inline